package com.legal.service.chat.impl;

import com.legal.domain.dto.ChatHistory;
import com.legal.domain.po.ChatMemoryMsg;
import com.legal.service.chat.AnalysisChatService;
import com.legal.service.chat.ChatHistoryService;
import com.legal.service.chat.FileService;
import com.legal.service.chat.ICasesService;
import com.legal.utils.BeanUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;

@RequiredArgsConstructor
@Service
@Slf4j
public class AnalysisChatServiceImpl implements AnalysisChatService {

    private final ChatClient analysisClient;
    private final ChatHistoryService historyService;
    private final FileService fileService;
    private final ICasesService casesService;


    /**
     * 案件分析，可以根据文件进行案件分析
     * @param chatMemoryMsg
     * @return
     */
    public Flux<String> chat(ChatMemoryMsg chatMemoryMsg) {
        //保存历史记录
        saveHistory(chatMemoryMsg);
        String fullPrompt = String.format("用户问题：%s \n end\n用户编号：%s\n会话ID：%s", chatMemoryMsg.getPrompt(), chatMemoryMsg.getUserNo(), chatMemoryMsg.getChatId());
        return analysisClient.prompt()
                .user(fullPrompt) //用户输入的问题
                .advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatMemoryMsg.getChatId()))
                .stream() //表示流式调用，会一直返回数据，直到数据结束
                .content();

    }
   /* @Override
    public Flux<String> chat(ChatMemoryMsg chatMemoryMsg, MultipartFile file) {
        saveHistory(chatMemoryMsg);
        //2. 根据会话id获取本地保存的文件
        Resource localfile = fileService.getFile(chatMemoryMsg.getChatId());
        if(!localfile.exists()){
            // 文件不存在
            throw new RuntimeException("文件不存在或者已经失效！");
        }
        //3. 请求模型
        return analysisClient.prompt()
                .user(chatMemoryMsg.getPrompt())
                // .advisors()方法通常用于向请求添加额外的参数或配置,
                // 1) "CHAT_MEMORY_CONVERSATION_ID_KEY":将当前对话与特定的聊天ID关联起来，以便维护对话上下文
                //     通过ChatId并结合RedisChatMemory类获取对话的上下文
                .advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatMemoryMsg.getChatId()))

                // 2) 按文件名过滤内容
//                .advisors(a -> a.param(FILTER_EXPRESSION, "file_name == '"+file.getFilename()+"'"))
                .stream() //表示流式调用，会一直返回数据，直到数据结束
                .content();
    }*/

    /**
     * 文件下载
     * @param chatId
     * @return
     */
    @Override
    public ResponseEntity<Resource> download(String chatId) {
        // 1.读取文件
        Resource resource = fileService.getFile(chatId);
        if (!resource.exists()) {
            return ResponseEntity.notFound().build();
        }
        // 2.文件名编码，写入响应头
        String filename = URLEncoder.encode(Objects.requireNonNull(resource.getFilename()), StandardCharsets.UTF_8);
        // 3.返回文件
        return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_OCTET_STREAM) // 设置响应内容类型为PDF
                .header("Content-Disposition", "attachment; filename=\"" + filename + "\"")
                .body(resource);
    }

    /**
     * 文件上传
     * @param id
     * @param file
     * @return
     */
    @Override
    public void save(Integer id, MultipartFile file) {
        //1.解析文件
        String fileContent = fileService.ParseFile(file);
        //2.保存文件内容到数据库
        casesService.updateCaseContent(id,fileContent);
    }

    /**
     * 保存历史会话
     * @param chatMemoryMsg
     */
    private void saveHistory(ChatMemoryMsg chatMemoryMsg) {
        //1.获取历史会话
        List<String> chatIds = historyService.getChatIds(chatMemoryMsg.getType(), chatMemoryMsg.getUserNo());
        //2.判断是chatIds中否有会话chatId
        if(!chatIds.contains(chatMemoryMsg.getChatId())) {
            //2.1 说明redis中没有会话记录，则为第一次，创建一个会话，创建默认的title, 比如用户输入的prompt的前10个字
            String title = chatMemoryMsg.getPrompt().length() > 10
                    ? chatMemoryMsg.getPrompt().substring(0, 10) + "..."
                    : chatMemoryMsg.getPrompt();
            //2.2 拷贝一个历史会话
            ChatHistory history = BeanUtil.copy(chatMemoryMsg, ChatHistory.class);
            history.setTitle(title);
            //2.3 保存历史记录会话
            historyService.save(history);
        }else{
            //3.如果有会话chatId，则只更新会话id时间，让其排序在前，更新的是Zset
            ChatHistory history = BeanUtil.copy(chatMemoryMsg, ChatHistory.class);
            //3.2 更新会话时间
            historyService.updateChatTime(history);
        }
    }


    /*//将文件写入向量库
    private void writeToVectorStore(Resource resource, String fileName, String chatId) {
        // 1.创建PDF的读取器
        PagePdfDocumentReader reader = new PagePdfDocumentReader(
                resource, // 文件源
                PdfDocumentReaderConfig.builder()
                        .withPageExtractedTextFormatter(ExtractedTextFormatter.defaults())
                        .withPagesPerDocument(1) // 每1页PDF作为一个Document
                        .build()
        );
        // 2.读取PDF文档，拆分为Document
        List<Document> documents = reader.read();
        // 3.给每个Document添加前缀，方便后续查询
        documents = documents.stream()
                .map(doc -> {
                    String prefixedId = chatId+":"+fileName+":" + doc.getId();
                    return new Document(prefixedId, doc.getText(), doc.getMetadata());
                })
                .collect(Collectors.toList());

        // 3.批量写入向量库
        int batchSize = 10;
        for (int i = 0; i < documents.size(); i += batchSize) {
            int end = Math.min(i + batchSize, documents.size());
            List<Document> batch = documents.subList(i, end);
            vectorStore.add(batch); // 分批写入向量存储
        }
    }*/
}
